﻿// -------------------------------------------------------------------------------------------------------------------------------
// <copyright file="TestSolve.cs" company="Exul">
//     Copyright (c) Exul. All rights reserved.
// </copyright>
// <author>
//     Exul
// </author>
// -------------------------------------------------------------------------------------------------------------------------------

namespace ExulLibrary.Mathematics.LinearAlgebra.Sequential.Tests.GmresSolverTest.DoubleExtensions
{
    #region Usings

    using System.Collections.Generic;

    using ExulLibrary.Mathematics.LinearAlgebra.Sequential.DoubleExtensions;

    using NUnit.Framework;

    #endregion

    /// <summary>
    ///     Test suite for <see cref="SlaeSolver{T}.Solve(Slae{T}, DenseVector{T})"/>.
    /// </summary>
    [TestFixture]
    [Category("ExulLibrary.Mathematics.LinearAlgebra.Sequential.DoubleExtensions.GmresSolver")]
    public sealed class TestSolve
    {
        #region Methods

        #region public

        /// <summary>
        ///     Tests the method when matrix has <see cref="CrcsSparseMatrix{T}"/> type.
        /// </summary>
        [Test]
        public void WhenMatrixHasCrcsSparseMatrixType()
        {
            // Arrange
            // Matrix:
            // 1 2 0  3
            // 0 3 0 12
            // 2 8 5 47
            // 6 0 0 25
            var matrix = new CrcsSparseMatrix<double>(
                lowTriangleRowsBegins: new[] { 0, 0, 0, 2, 3 },
                lowTriangleColumnsIndexes: new[] { 0, 1, 0 },
                highTriangleColumnsBegins: new[] { 0, 0, 1, 1, 4 },
                highTriangleRowsIndexes: new[] { 0, 0, 1, 2 },
                lowTriangleData: new double[] { 2, 8, 6 },
                diagonalData: new double[] { 1, 3, 5, 25 },
                highTriangleData: new double[] { 2, 3, 12, 47 });
            var rightHandPart = new DenseVector<double>(new double[] { 3021, 12030, 47582, 25006 });
            var slae = new Slae<double>(matrix, rightHandPart);

            var solver = new GmresSolver();
            solver.Initialize(
                matrix.RowsCount,
                new DoubleResidualStopCriterion(1e-8),
                new Dictionary<string, object>
                {
                    { "spatialdimension", 5 }
                });

            var solution = new DenseVector<double>(4);

            var expectedSolution = new DenseVector<double>(new double[] { 1, 10, 100, 1000 });

            // Act
            solver.Solve(slae, solution);

            // Assert
            for (var index = 0; index < expectedSolution.Length; index++)
            {
                Assert.That(solution.GetAt(index), Is.EqualTo(expectedSolution.GetAt(index)).Within(1e-8));
            }
        }

        /// <summary>
        ///     Tests the method when matrix has <see cref="CrcsSparseSymmetricMatrix{T}"/> type.
        /// </summary>
        [Test]
        public void WhenMatrixHasCrcsSparseSymmetricMatrixType()
        {
            // Arrange
            // Matrix:
            //  6 12  18  24
            // 12 31   0   0
            // 18  0  62 112
            // 24  0 112 305
            var matrix = new CrcsSparseSymmetricMatrix<double>(
                new[] { 0, 0, 1, 2, 4 },
                new[] { 0, 0, 0, 2 },
                new double[] { 6, 31, 62, 305 },
                new double[] { 12, 18, 24, 112 });
            var rightHandPart = new DenseVector<double>(new double[] { 25926, 322, 118218, 316224 });
            var slae = new Slae<double>(matrix, rightHandPart);

            var solver = new GmresSolver();
            solver.Initialize(
                matrix.RowsCount,
                new DoubleResidualStopCriterion(1e-8),
                new Dictionary<string, object>
                {
                    { "spatialdimension", 5 }
                });

            var solution = new DenseVector<double>(4);

            var expectedSolution = new DenseVector<double>(new double[] { 1, 10, 100, 1000 });

            // Act
            solver.Solve(slae, solution);

            // Assert
            for (var index = 0; index < expectedSolution.Length; index++)
            {
                Assert.That(solution.GetAt(index), Is.EqualTo(expectedSolution.GetAt(index)).Within(1e-8));
            }
        }

        #endregion

        #endregion
    }
}